package org.mbds.android.sismapp.activity;

import java.util.ArrayList;
import java.util.Locale;

import org.mbds.android.p2p.services.P2pService;
import org.mbds.android.p2p.services.P2pServiceMessageHandler;
import org.mbds.android.sismapp.R;
import org.mbds.android.sismapp.SismappApplication;
import org.mbds.android.sismapp.SismappMenu;
import org.mbds.android.sismapp.SismappMessage;
import org.mbds.android.sismapp.SismappStaticCommons;
import org.mbds.android.sismapp.sensors.SensorData;
import org.mbds.android.sismapp.sensors.SensorObserverInterface;
import org.mbds.android.sismapp.sensors.SensorsDataManager;
import org.mbds.android.tools.FileUtilities;

import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.media.AudioManager;
import android.media.ToneGenerator;
import android.os.Bundle;
import android.os.IBinder;
import android.os.Message;
import android.os.Messenger;
import android.os.RemoteException;
import android.speech.tts.TextToSpeech;
import android.speech.tts.TextToSpeech.OnInitListener;
import android.view.KeyEvent;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.WindowManager;
import android.view.WindowManager.LayoutParams;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.CheckBox;
import android.widget.EditText;
import android.widget.Spinner;
import android.widget.Toast;

public class SensorDataCollectorActivity extends Activity implements
		SensorObserverInterface /* , OnItemSelectedListener */, OnInitListener {

	public String selectedActivity;
	private static TextToSpeech tts = null;
	// private static boolean isFist = false;
	// Pour tester en "dur" avec le Samsung Galaxy Note 2 (delay fastest)
	private final static int NB_PEAKS_MAX_NOTE2 = 4;
	private final static int NB_PEAKS_MIN_NOTE2 = 1;
	private final static float Y_MAX_MAX_NOTE2 = 7;
	private final static float Y_MAX_MIN_NOTE2 = 0.8f;
	private final static float Y_MAX_MIN_REPOS_NOTE2 = -0.5f;
	private final static float Y_MAX_MAX_REPOS_NOTE2 = 0.5f;

	// Pour tester en "dur" avec le Samsung Nexus S (delay fastest)
	private final static int NB_PEAKS_MAX_NEXUS = 20;
	private final static int NB_PEAKS_MIN_NEXUS = 8;
	private final static float Y_MAX_MAX_NEXUS = 10;
	private final static float Y_MAX_MIN_NEXUS = 1f;
	private final static float Y_MAX_MIN_REPOS_NEXUS = -0.5f;
	private final static float Y_MAX_MAX_REPOS_NEXUS = 0.5f;

	private static boolean isThreadRunning = false;
	
	//Pour assurer l'intéraction avec le service
	public static Messenger p2pServiceInterface; // Interface pour communiquer avec la partie P2P.
	private static Messenger p2pMessengerThis;
	private static boolean p2pServiceInterfaceBound = false;
	public static ServiceConnection mServiceConnection;
	public static boolean ConnexionToService = false;
	public static Intent mServiceIntent;
	


	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_sensors);
		
		WindowManager.LayoutParams params = getWindow().getAttributes();
		params.flags |= LayoutParams.FLAG_KEEP_SCREEN_ON;
		getWindow().setAttributes(params);
		p2pMessengerThis = new Messenger(new P2pServiceMessageHandler(this));
		tts = new TextToSpeech(getApplicationContext(), this);
		
		final CheckBox detect = (CheckBox) findViewById(R.id.check_box_talk);
		
		detect.setOnClickListener(new View.OnClickListener() {

            public void onClick(View view) {
                // TODO Auto-generated method stub
                if(detect.isChecked()){
                    setThreadRunning(false);
                }else{
                	setThreadRunning(true);
                }
            }
        });
		
		
final CheckBox save = (CheckBox) findViewById(R.id.check_box_save);
		
		save.setOnClickListener(new View.OnClickListener() {

            public void onClick(View view) {
                // TODO Auto-generated method stub
                if(save.isChecked()){
                	FileUtilities.saveDataToFile(SensorsDataManager.nameOfFile, SensorsDataManager.HEADER);
                }else{
                	System.out.println("Un-Checked");
                }
            }
        });

		Button Start = (Button) findViewById(R.id.Start_button);

		Start.setOnClickListener(new View.OnClickListener() {

			public void onClick(View view) {
				try {
					Toast.makeText(getApplicationContext(),
							"Data collection started", Toast.LENGTH_SHORT)
							.show();
					startRegistering(view);
					// new ProcessSensorData(datas)

				} catch (Exception e) {

				}
			}

		});

		//final int ok = SensorsDataManager.retrieveDataFromDB();

		Button Stop = (Button) findViewById(R.id.Stop_button);

		Stop.setOnClickListener(new View.OnClickListener() {

			public void onClick(View view) {
				try {

					stopRegistering();
					Toast.makeText(getApplicationContext(),
							"Data collection stopped", Toast.LENGTH_SHORT)
							.show();
					//Toast.makeText(getApplicationContext(),"Nombre de donn�es collect�es: " + ok, Toast.LENGTH_LONG).show();

				} catch (Throwable e) {
					e.printStackTrace();
				}
			}

		});
		
		mServiceIntent = new Intent(this, P2pService.class);
		mServiceConnection = new ServiceConnection() {
			
			@Override
			public void onServiceDisconnected(ComponentName name) {
				p2pServiceInterfaceBound = false;
				Toast.makeText(getApplicationContext(),"SERVICE UNBOUND ", Toast.LENGTH_SHORT).show();
			}
			
			@Override
			public void onServiceConnected(ComponentName name, IBinder service) {
				p2pServiceInterface = new Messenger(service); // Keep a reference to the service, in order to communicate with it.
				
				//Send a local reference to the service, so that it can sent back messages.
				Message msg = Message.obtain(null, P2pService.TYPE_NEW_CLIENT);
				msg.replyTo = p2pMessengerThis;
				try {
					p2pServiceInterface.send(msg);
				} catch (RemoteException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
				p2pServiceInterfaceBound = true;
				Toast.makeText(getApplicationContext(),"SERVICE BOUND BOUND ", Toast.LENGTH_SHORT).show();

			}
		};

		bindService(mServiceIntent, mServiceConnection, Context.BIND_AUTO_CREATE);
	}

	@Override
	public void onResume() {
		super.onResume();

	}
	
	@Override
	public void onDestroy(){
		super.onDestroy();
		if(p2pServiceInterfaceBound)
			unbindService(mServiceConnection);
		
	}

	/*
	 * The 2 following methods are called when either start or stop button are
	 * pressed in this respectively
	 */
	public void startRegistering(View v) {
		
		SensorsDataManager.accelerometerData.addObserver(this);
		
		SensorsDataManager.accelerometerData.startDataCollection(selectedActivity);
		
	}

	public void stopRegistering() throws Throwable {
		
		SensorsDataManager.accelerometerData.stopDataCollection();
		
		SensorsDataManager.accelerometerData.removeObserver(this);
	
	}

	public void stopDataCollection() {
		
	}

	@Override
	public void finish() {
		try {
			stopRegistering();
		} catch (Throwable e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}


	public void updateSensorData(ArrayList<SensorData> data,
			double lastDeltaTime, SensorData lastValues) {
		// Run within a Thread the data recognition
		if (!isThreadRunning) {
			isThreadRunning = true;
			ProcessSensorData p = new ProcessSensorData(data);
		}
	}

	/**
	 * Thread to analyse every 1 second the data from sensors
	 * 
	 * 
	 */

	class ProcessSensorData extends Thread {
		ArrayList<SensorData> data;

		public ProcessSensorData(ArrayList<SensorData> datas) {
			setThreadRunning(true);
			this.data = datas;
			start();
		}

		public void run() {
			// Process for nexus s
			if (SismappStaticCommons.getDeviceName().toUpperCase().contains("NEXUS S")) {
				nexus(data);
			}
			if (SismappStaticCommons.getDeviceName().toUpperCase().contains("GT-N7100")) 
			{
				System.out.println("device name: " + SismappStaticCommons.getDeviceName().toUpperCase() );
				note2(data);
			}
			setThreadRunning(false);
		}
	}
	
	public void nexus(ArrayList<SensorData> data) {
		int size = data.size();
		if (size > 0) {
			float val_n = 9999;
			float val_nPlus1 = 9999;
			float val_nMoins1 = 0;
			ArrayList<Float> peaks = new ArrayList<Float>();
			boolean ok_marche = true;
			boolean ok_course = false;
			boolean ok_secouer = false;
			boolean ok_repos = false;
			String debug = "";
			float[] values = new float[size];
			// Get peaks values
			for (int i = 0; i < size; i++) {
				SensorData s = data.get(i);
				synchronized (s) {
					float val = s.val[1];
					debug += val + ";";
					values[i] = val;
				}
			}
			for (int x = 0; x < size; x++) {
				val_nMoins1 = val_n;
				val_n = values[x];
	
				if (x < size - 1) {
					val_nPlus1 = values[x + 1];
					System.out.println("VAL_Nmoins1: " + val_nMoins1
							+ " VAL_N: " + val_n + " VAL_nPLUS1: "
							+ val_nPlus1);
					if (val_nPlus1 < val_n && val_n > val_nMoins1) {
						peaks.add(val_n);
					}
				}
			}
	
			System.out.println("NBRES de Peaks: " + peaks.size());
			System.out.println("Data : " + debug);
	
			// Check if user is walking or running
			if (peaks.size() <= NB_PEAKS_MAX_NEXUS
					&& peaks.size() >= NB_PEAKS_MIN_NEXUS) {
				for (int n = 0; n < peaks.size(); n++) {
					float val = peaks.get(n);
					if (val > Y_MAX_MAX_NEXUS - 1)
						ok_course = true;
					if (val < Y_MAX_MIN_NEXUS || val > Y_MAX_MAX_NEXUS) {
						ok_marche = false;
					}
				}
			} else {
				ok_marche = false;
			}
			if (ok_marche) {
				if (ok_course)
					textToSpeech("run", "RUN");
				else
					textToSpeech("walk", "WALK");
			} else {
				// Check other activities
	
				// Check mobile shake
				ok_secouer = false;
				for (int n = 0; n < size; n++) {
					if (values[n] > Y_MAX_MAX_NEXUS)
						ok_secouer = true;
				}
				
				if (ok_secouer) {
					textToSpeech("Shake", "SHAKE");
					// Send message DYFI on SISMAPP network
					try {
						SismappMessage.sendSismappMessage(SismappMessage.MESSAGE_DYFI);
					} catch (Exception e) {
						textToSpeech(e.getMessage(), "ERROR SENDING MESSAGE");
					}
				} else {
					// Check mobile sleep
					ok_repos = false;
					if (size == 0) {
						ok_repos = true;
					} else {
						ok_repos = true;
						for (int n = 0; n < size; n++) {
							float val = values[n];
							if (val < Y_MAX_MIN_REPOS_NEXUS
									|| val > Y_MAX_MAX_REPOS_NEXUS)
								ok_repos = false;
						}
					}
					if (ok_repos) {
						textToSpeech("Sleep", "SLEEP");
					}
				}
			}
		}
	}

	
	public void note2(ArrayList<SensorData> data){
		
		float val_n_Y = 9999;
		float val_n_X = 9999;
		float val_n_Z = 9999;
		float val_nPlus1 = 9999;
		float val_nMoins1 = 0;
		
		ArrayList<Float> valeurs_y = new ArrayList<Float>();
		
		boolean ok_marche = false;
		boolean ok_course = false;	
		boolean ok_secouer = false;
		boolean ok_repos = false;
		boolean ok_ok = false;
		int num_pics = 0;
		
		
		String debug = "Val_N :";
		
	for (int i = 0; i<data.size();i++) {
			val_nMoins1=val_n_Y;
			
			val_n_Y = data.get(i).val[1];
			val_n_X = data.get(i).val[0];
			val_n_Z = data.get(i).val[2];
			
			double time = (data.get(i).time*SensorsDataManager.MULT_NANO)-(data.get(0).time*SensorsDataManager.MULT_NANO);
			if (i<data.size()-1) {
				int j = i+1;
				val_nPlus1=data.get(j).val[1];
			}
	
			
			//System.out.println("VAL_Nmoins1: " + val_nMoins1 + "VAL_N: " + val_n_Y + "VAL_nPLUS1: " +val_nPlus1);
			
		}
		System.out.println("VAL_N: " + val_n_Y);
		
		//if(val_n_Y >= -0.25 && val_n_Y <=0.1)
			//ok_repos = true;
		//else if ((val_n_Y>= -1 && val_n_Y < -0.30) || (val_n_Y > 0.3 && val_n_Y <=2) )
			//ok_marche =true;
		//else if ((val_n_Y>= -6 && val_n_Y < -1) || (val_n_Y > 2 && val_n_Y < 8) )
			//ok_course =true;
		//else if ((val_n_Y>= -20 && val_n_Y < -6) || (val_n_Y > 8 && val_n_Y < 20) )
			//ok_secouer = true;
		//else
			///ok_ok = true;
		boolean send = false; 
		if ((val_n_Y>= -20 && val_n_Y < -6) || (val_n_Y > 8 && val_n_Y < 20) ){
			ok_secouer = true;
			
			
			try {
				if (!send){
					SismappMessage.sendSismappMessage(SismappMessage.MESSAGE_DYFI);
					send = true;
				}				
			} catch (Exception e) {
				textToSpeech(e.getMessage(), "ERROR SENDING MESSAGE");
			} 
		
		}
		
			
		
	//} 
		
	if (ok_repos) {			
		final ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100);
	     tg.startTone(ToneGenerator.TONE_PROP_BEEP);		
		textToSpeech("Sleep", "Activit� MARCHE");
	}
	if (ok_secouer) {
		final ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100);
	     tg.startTone(ToneGenerator.TONE_PROP_BEEP);		
		textToSpeech("shake", "Activit� MARCHE");
	}
	if (ok_marche) {
		final ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100);
	     tg.startTone(ToneGenerator.TONE_PROP_BEEP);		
		textToSpeech("walk", "Activit� MARCHE");
	}
	if (ok_course) {
		final ToneGenerator tg = new ToneGenerator(AudioManager.STREAM_NOTIFICATION, 100);
	     tg.startTone(ToneGenerator.TONE_PROP_BEEP);		
		textToSpeech("Run", "Activit� MARCHE");
	}
		
		setThreadRunning(false);
	}
		
	

	/**
	 * Convert text to speech
	 * 
	 * @param text
	 * @return
	 */
	public static boolean textToSpeech(String message, String title) {
		boolean res = false;
		if (tts != null) {
			res = tts.speak(message, TextToSpeech.QUEUE_FLUSH, null) == 0;
		}
		return res;
	}

	public void onInit(int status) {
		if (status == TextToSpeech.SUCCESS) {
			tts.setLanguage(Locale.ENGLISH);
		}
	}

	public static boolean isThreadRunning() {
		return isThreadRunning;
	}

	public static void setThreadRunning(boolean isThreadRunning) {
		SensorDataCollectorActivity.isThreadRunning = isThreadRunning;
	}


	/***********************/
	/* Create options menu */
	/***********************/
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		SismappMenu.onCreateOptionsMenu(this, menu);
		return super.onCreateOptionsMenu(menu);
	}

	/************************/
	/* Prepare options menu */
	/************************/
	@Override
	public boolean onPrepareOptionsMenu(Menu menu) {
		SismappMenu.onPrepareOptionsMenu(this, menu);
		return super.onPrepareOptionsMenu(menu);
	}

	/*******************************/
	/* Manage menu item selection */
	/*******************************/
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		SismappMenu.onOptionsItemSelected(this, item);
		return super.onOptionsItemSelected(item);
	}
	
	public SensorDataCollectorActivity getInstance(){
		return SensorDataCollectorActivity.this;
	}
}
